//! Plugin integration tests
//! 
//! Tests for the Extism plugin system integration

use ai_test_platform::{
    actors::ActorSystemManager,
    models::{Value, ValueMap},
    plugins::{extism_wrapper::ExtismPluginManager, PluginManager},
};
use serde_json::json;

#[tokio::test]
async fn test_plugin_manager_creation() {
    let manager = ExtismPluginManager::new();
    
    // Should have default search paths
    assert!(!manager.search_paths().is_empty());
}

#[tokio::test]
async fn test_plugin_manager_search_paths() {
    let mut manager = ExtismPluginManager::new();
    let initial_count = manager.search_paths().len();
    
    // Add a new search path
    manager.add_search_path("/custom/plugin/path".to_string());
    assert_eq!(manager.search_paths().len(), initial_count + 1);
    
    // Adding the same path again should not increase count
    manager.add_search_path("/custom/plugin/path".to_string());
    assert_eq!(manager.search_paths().len(), initial_count + 1);
}

#[tokio::test]
async fn test_plugin_actor_integration() {
    let mut actor_system = ActorSystemManager::new().await.unwrap();
    actor_system.initialize().await.unwrap();

    let plugin_actor = actor_system.plugin_actor().unwrap();

    // Test plugin actor is accessible
    assert!(!plugin_actor.actor_id().is_empty());
}

#[tokio::test]
async fn test_builtin_plugin_manager() {
    let mut manager = PluginManager::new();
    
    // Test loading builtin plugins
    let result = manager.load_builtin_plugins().await;
    assert!(result.is_ok());
    
    // Should have some builtin plugins loaded
    let plugins = manager.list_plugins().await.unwrap();
    assert!(!plugins.is_empty());
}

#[tokio::test]
async fn test_plugin_function_call_format() {
    // Test the expected format for plugin function calls
    let request = json!({
        "method": "GET",
        "url": "https://api.example.com/test",
        "headers": {
            "Content-Type": "application/json"
        }
    });
    
    let args = vec![Value::from(request)];
    
    // Should be able to serialize arguments
    let serialized = serde_json::to_string(&args).unwrap();
    assert!(serialized.contains("GET"));
    assert!(serialized.contains("https://api.example.com/test"));
}

#[tokio::test]
async fn test_plugin_response_format() {
    // Test the expected format for plugin responses
    let response = json!({
        "status": 200,
        "headers": {
            "content-type": "application/json"
        },
        "body": "{\"message\": \"success\"}",
        "elapsed_ms": 150
    });
    
    // Should be able to parse as Value
    let value = Value::from(response);
    assert!(value.is_object());
    
    if let Value::Object(obj) = value {
        assert!(obj.contains_key("status"));
        assert!(obj.contains_key("body"));
        assert!(obj.contains_key("elapsed_ms"));
    }
}

#[tokio::test]
async fn test_plugin_configuration() {
    let mut config = ValueMap::new();
    config.insert("timeout".to_string(), Value::from(30));
    config.insert("user_agent".to_string(), Value::from("AI-Test-Platform/1.0"));
    config.insert("follow_redirects".to_string(), Value::from(true));
    
    // Configuration should be serializable
    let serialized = serde_json::to_string(&config).unwrap();
    assert!(serialized.contains("timeout"));
    assert!(serialized.contains("AI-Test-Platform"));
}

#[tokio::test]
async fn test_plugin_error_handling() {
    let manager = ExtismPluginManager::new();
    
    // Test loading non-existent plugin
    let mut manager_mut = ExtismPluginManager::new();
    let result = manager_mut.load_plugin("non_existent_plugin.wasm", ValueMap::new()).await;
    assert!(result.is_err());
}

#[tokio::test]
async fn test_plugin_lifecycle() {
    let mut manager = ExtismPluginManager::new();
    
    // Test the complete plugin lifecycle would work
    // (We can't actually load WASM files in tests without building them first)
    
    // 1. Load plugin (would fail with non-existent file, but that's expected)
    let load_result = manager.load_plugin("test_plugin.wasm", ValueMap::new()).await;
    assert!(load_result.is_err()); // Expected to fail since file doesn't exist
    
    // 2. The rest of the lifecycle would be:
    // - Call functions on the plugin
    // - Update configuration
    // - Unload plugin
}

#[tokio::test]
async fn test_plugin_manifest_structure() {
    use ai_test_platform::models::plugin::{PluginManifest, PluginType};
    
    let manifest = PluginManifest::new(
        "test-plugin".to_string(),
        "1.0.0".to_string(),
        PluginType::Wasm,
    );
    
    assert_eq!(manifest.name, "test-plugin");
    assert_eq!(manifest.version, "1.0.0");
    assert_eq!(manifest.plugin_type, PluginType::Wasm);
}

#[tokio::test]
async fn test_plugin_registry_operations() {
    use ai_test_platform::plugins::PluginRegistry;
    
    let mut registry = PluginRegistry::new();
    
    // Test registry operations
    let plugin_info = json!({
        "name": "test-plugin",
        "version": "1.0.0",
        "description": "Test plugin for integration tests"
    });
    
    registry.register_plugin("test-plugin".to_string(), plugin_info.clone());
    
    let retrieved = registry.get_plugin_info("test-plugin");
    assert!(retrieved.is_some());
    assert_eq!(retrieved.unwrap()["name"], "test-plugin");
}
